home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / DOCMANAG.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  44.7 KB  |  1,789 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.28  $
  6. //
  7. // Implementation of class TDocManager
  8. //----------------------------------------------------------------------------
  9. #pragma hdrignore SECTION
  10. #include <owl/pch.h>
  11. #if !defined(OWL_DOCMANAG_H)
  12. # include <owl/docmanag.h>
  13. #endif
  14. #if !defined(OWL_APPDICT_H)
  15. # include <owl/appdict.h>
  16. #endif
  17. #if !defined(OWL_OPENSAVE_H)
  18. # include <owl/opensave.h>
  19. #endif
  20. #if !defined(OWL_PICKLIST_H)
  21. # include <owl/picklist.h>
  22. #endif
  23. #if !defined(WINSYS_SYSTEM_H)
  24. # include <winsys/system.h>
  25. #endif
  26. #if !defined(CLASSLIB_FILENAME_H)
  27. # include <classlib/filename.h>
  28. #endif
  29. #if !defined(OWL_DOCVIEW_RH)
  30. # include <owl/docview.rh>
  31. #endif
  32. #include <string.h>
  33. #include <stdio.h>
  34. #include <dlgs.h>
  35.  
  36. //
  37. // (Readable versions of) IDs of controls used by CommonDialogs
  38. //
  39. #define IDC_FILENAMETXT       stc3
  40. #define IDC_FILENAME          edt1
  41. #define IDC_FILELIST          lst1
  42. #define IDC_CURDIR            stc1
  43. #define IDC_DIRLIST           lst2
  44. #define IDC_FILETYPEEXT       stc2
  45. #define IDC_FILETYPES         cmb1
  46. #define IDC_DRIVESTEXT        stc4
  47. #define IDC_DRIVES            cmb2
  48. #define IDC_HELPF             pshHelp
  49. #define IDC_READONLY          chx1
  50.  
  51. typedef TDocTemplate*         TDocTemplatePtr;
  52.  
  53. OWL_DIAGINFO;
  54. #if defined(SECTION) && SECTION != 1
  55. DIAG_DECLARE_GROUP(OwlDocView);        // General Doc/View diagnostic group
  56. #endif
  57.  
  58. #if !defined(SECTION) || SECTION == 1
  59.  
  60. DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlDocView, 1, 0);
  61.  
  62. //---------------------------------------------------------------------------
  63. // class TDvOpenSaveData
  64. //
  65.  
  66. //
  67. // Constructor of class representing the data to be displayed in the
  68. // Open/Save dialogs used by the DocManager.
  69. //
  70. TDvOpenSaveData::TDvOpenSaveData(uint32 flags, char* filter,
  71.                                  char* initialDir,
  72.                                  char* defExt,
  73.                                  int filterIndex, TDocTemplate **tmplList,
  74.                                  int tmplCount)
  75. :
  76.  TOpenSaveDialog::TData(flags, filter, 0/*customFilter*/,
  77.                         initialDir, defExt, 0/*maxPath*/, filterIndex),
  78.  TmplList(tmplList),
  79.  TmplCount(tmplCount)
  80. {
  81. }
  82.  
  83. //
  84. // Constructor of mixin. class used by the DocManager's version of the
  85. // Open/Save dialogs.
  86. //
  87. TDvOpenSaveDataOwner::TDvOpenSaveDataOwner(TDvOpenSaveData& data)
  88. :
  89.   DvData(data)
  90. {
  91. }
  92.  
  93. //
  94. //'HandleTemplateChanged' is invoked whenever the user switches the
  95. // file type in the FileOpen or FileSave dialog. The function updates
  96. // the internal OPENFILENAME structure based on the properties of the
  97. // new template selected.
  98. //
  99. static void
  100. handleTemplateChanged(TDialog& dialog,
  101.                       TDvOpenSaveDataOwner& dataOwner,
  102.                       OPENFILENAME& ofn)
  103. {
  104.   int index = (int)dialog.SendDlgItemMsg(IDC_FILETYPES, CB_GETCURSEL, 0, 0);
  105.   if (index >= 0) {
  106.     CHECK(index < dataOwner.GetTmplCount());
  107.     TDocTemplate* tpl = dataOwner.GetTmplList()[index];
  108.  
  109.     // Update default extension in OFN structure
  110.     //
  111.     CHECK(ofn.lpstrDefExt);
  112.     ofn.lpstrDefExt = tpl->GetDefaultExt();
  113.   }
  114. }
  115.  
  116. //---------------------------------------------------------------------------
  117. // class TDvFileOpenDialog
  118. //
  119.  
  120. //
  121. // Constructor of object encapsulating the Open File dialog used by the
  122. // DocManager.
  123. //
  124. TDvFileOpenDialog::TDvFileOpenDialog(TWindow* parent, TDvOpenSaveData& data,
  125.                                      const char* title)
  126. :
  127.   TFileOpenDialog(parent, data, 0/*templateId*/, title),
  128.   TDvOpenSaveDataOwner(data)
  129. {
  130. }
  131.  
  132. //
  133. // Overriden virtual function of TFileOpenDialog to allow us to detect when
  134. // the user switches between file types [i.e. DocView templates].
  135. //
  136. bool
  137. TDvFileOpenDialog::DialogFunction(uint message, TParam1 p1, TParam2 p2)
  138. {
  139. #if defined(BI_PLAT_WIN32)
  140.   if (message == WM_COMMAND && LOWORD(p1) == IDC_FILETYPES &&
  141.                                HIWORD(p1) == CBN_SELCHANGE) {
  142. #else //  BI_PLAT_WIN16
  143.   if (message == WM_COMMAND && LOWORD(p1) == IDC_FILETYPES &&
  144.                                HIWORD(p2) == CBN_SELCHANGE) {
  145. #endif
  146.     handleTemplateChanged(*this, *this, GetOFN());
  147.   }
  148.  
  149.   return TFileOpenDialog::DialogFunction(message, p1, p2);
  150. }
  151.  
  152. //---------------------------------------------------------------------------
  153. // class TDvFileSaveDialog
  154. //
  155.  
  156. //
  157. // Constructor of object encapsulating the FileSave dialog used by the
  158. // DocManager.
  159. //
  160. TDvFileSaveDialog::TDvFileSaveDialog(TWindow* parent, TDvOpenSaveData& data,
  161.                                      const char* title)
  162. :
  163.   TFileSaveDialog(parent, data, 0/*templateId*/, title),
  164.   TDvOpenSaveDataOwner(data)
  165. {
  166. }
  167.  
  168. //
  169. // Overriden virtual function of TFileOpenDialog to allow us to detect when
  170. // the user switches between file types [i.e. DocView templates].
  171. //
  172. bool
  173. TDvFileSaveDialog::DialogFunction(uint message, TParam1 p1, TParam2 p2)
  174. {
  175. #if defined(BI_PLAT_WIN32)
  176.   if (message == WM_COMMAND && LOWORD(p1) == IDC_FILETYPES &&
  177.                                HIWORD(p1) == CBN_SELCHANGE) {
  178. #else //  BI_PLAT_WIN16
  179.   if (message == WM_COMMAND && LOWORD(p1) == IDC_FILETYPES &&
  180.                                HIWORD(p2) == CBN_SELCHANGE) {
  181. #endif
  182.     handleTemplateChanged(*this, *this, GetOFN());
  183.   }
  184.  
  185.   return TFileSaveDialog::DialogFunction(message, p1, p2);
  186. }
  187.  
  188. //----------------------------------------------------------------------------
  189. // class TDocManager
  190. //
  191.  
  192. DEFINE_RESPONSE_TABLE (TDocManager)
  193.   EV_WM_CANCLOSE,
  194.   EV_WM_PREPROCMENU,
  195.   EV_WM_WAKEUP,
  196.   EV_COMMAND(CM_FILENEW,           CmFileNew),
  197.   EV_COMMAND(CM_FILEOPEN,          CmFileOpen),
  198.   EV_COMMAND(CM_FILESAVE,          CmFileSave),
  199.   EV_COMMAND(CM_FILESAVEAS,        CmFileSaveAs),
  200.   EV_COMMAND(CM_FILEREVERT,        CmFileRevert),
  201.   EV_COMMAND(CM_FILECLOSE,         CmFileClose),
  202.   EV_COMMAND(CM_VIEWCREATE,        CmViewCreate),
  203.   EV_COMMAND_ENABLE(CM_FILENEW,    CeFileNew),
  204.   EV_COMMAND_ENABLE(CM_FILEOPEN,   CeFileOpen),
  205.   EV_COMMAND_ENABLE(CM_FILESAVE,   CeFileSave),
  206.   EV_COMMAND_ENABLE(CM_FILESAVEAS, CeFileSaveAs),
  207.   EV_COMMAND_ENABLE(CM_FILEREVERT, CeFileRevert),
  208.   EV_COMMAND_ENABLE(CM_FILECLOSE,  CeFileClose),
  209.   EV_COMMAND_ENABLE(CM_VIEWCREATE, CeViewCreate),
  210. END_RESPONSE_TABLE;
  211.  
  212. //
  213. // Constructor of DocManager
  214. //
  215. TDocManager::TDocManager(int mode, TApplication* app, TDocTemplate*& templateHead)
  216. {
  217.   Init(mode, app, templateHead);
  218. }
  219.  
  220. //
  221. // Common initialization for TDocManager constructors (above constructor, &
  222. // compatable constructor below)
  223. //
  224. void
  225. TDocManager::Init(int mode, TApplication* app, TDocTemplate*& templateHead)
  226. {
  227.   Mode = mode;
  228.   TemplateList = templateHead;
  229.   TemplateHead = &templateHead;
  230.   UntitledIndex= 0;
  231.  
  232.   PRECONDITION(app);
  233.   Application = app;
  234.  
  235.   // Update docmanger pointer members of static templates
  236.   //
  237.   for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate())
  238.     tpl->DocManager = this;
  239.  
  240. #if defined(OWL2_COMPAT)
  241.  
  242.   // Setup backward compatibility entry points
  243.   //
  244.   TDocTemplate::SelectSave_ = SelectSave;
  245.   TDocTemplate::InitDoc_    = InitDoc;
  246.   TDocTemplate::InitView_   = InitView;
  247. #endif
  248. }
  249.  
  250. //
  251. // Destruct this DocManager. Close all open documents (views close with them),
  252. // and delete all non-static doc templates
  253. //
  254. TDocManager::~TDocManager()
  255. {
  256.   // Iterate through document list, closing and deleting each
  257.   //
  258.   TDocument* doc;
  259.   while ((doc = DocList.Next(0)) != 0) {
  260.     if (doc->IsOpen())
  261.       doc->Close();
  262.  
  263.     // NOTE: deleting the document deletes all attached views, and unlinks
  264.     //       the document from the docmanager's document list
  265.     //
  266.     delete doc;
  267.  
  268.     // Flush (dispatch) any pending MDI-Child-destroy messages
  269.     //
  270.     GetApplication()->PumpWaitingMessages();
  271.   }
  272.  
  273.   // Reset the 'Docmanager' pointer of static templates and delete
  274.   // dynamic ones...
  275.   //
  276.   while (TemplateList) {
  277.     TDocTemplate* tpl = TemplateList;
  278.     TemplateList = tpl->GetNextTemplate();
  279.     if (tpl->IsStatic())
  280.       tpl->SetDocManager(0);
  281.     else
  282.       delete tpl;
  283.   }
  284. }
  285.  
  286. //----------------------------------------------------------------------------
  287.  
  288. //
  289. // Count the number of templates, filtering by document type and/or view
  290. // type as indicated.
  291. //
  292. int
  293. TDocManager::GetTemplateCount(TDocument* ofDocType, TView* ofViewType)
  294. {
  295.   // No registered templates!!
  296.   //
  297.   if (!TemplateList) {
  298.     TRACEX(OwlDocView, 0, "GetTemplateCount(): No registered templates!");
  299.     return 0;
  300.   }
  301.  
  302.   // Walk through template list matching doc/view types as indicated
  303.   //
  304.   int tplCount = 0;
  305.   for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate()) {
  306.     if (ofDocType && !tpl->IsMyKindOfDoc(*ofDocType))
  307.       continue;
  308.  
  309.     if (ofViewType && !tpl->IsMyKindOfView(*ofViewType))
  310.       continue;
  311.  
  312.     tplCount++;
  313.   }
  314.   return tplCount;
  315. }
  316.  
  317. //
  318. // Build a list of templates for creating new documents or opening existing
  319. // documents. Return the number of templates in the list. Passing 0 for
  320. // tplList skips the actual creation of the list, useful for pre-counting
  321. //
  322. #if __DEBUG < 2
  323. int
  324. TDocManager::GetNewTemplates(TDocTemplate** tplList, int, bool newDoc)
  325. #else
  326. int
  327. TDocManager::GetNewTemplates(TDocTemplate** tplList, int size, bool newDoc)
  328. #endif
  329. {
  330.   // Check for no registered templates
  331.   //
  332.   if (!TemplateList) {
  333.     TRACEX(OwlDocView, 0, "GetNewTemplates(): No registered templates!");
  334.     return 0;
  335.   }
  336.  
  337.   // Walk thru all of the templates looking for visible ones, and if a new
  338.   // doc, non-dtReadOnly ones.
  339.   //
  340.   int tplCount = 0;
  341.   for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate()) {
  342.     if (tpl->IsVisible() && !(tpl->IsFlagSet(dtReadOnly) && newDoc)) {
  343.       if (tplList) {
  344.         CHECK(tplCount < size);
  345.         tplList[tplCount] = tpl;
  346.       }
  347.       tplCount++;
  348.     }
  349.   }
  350.   return tplCount;
  351. }
  352.  
  353. //
  354. // Build a list of templates for saving documents. Return the number of
  355. // templates in the list. Passing 0 for tplList skips the actual creation of
  356. // the list, useful for pre-counting
  357. //
  358. #if __DEBUG < 2
  359. int
  360. TDocManager::GetSaveTemplates(TDocTemplate** tplList, int,
  361.                               TDocument& doc, bool sameDoc)
  362. #else
  363. int
  364. TDocManager::GetSaveTemplates(TDocTemplate** tplList, int size,
  365.                               TDocument& doc, bool sameDoc)
  366. #endif
  367. {
  368.   // Check for no registered templates
  369.   //
  370.   if (!TemplateList) {
  371.     TRACEX(OwlDocView, 0, "GetSaveTemplates(): No registered templates!");
  372.     return 0;
  373.   }
  374.  
  375.   // Walk thru all of the templates looking for visible, non-dtReadOnly ones,
  376.   // and if the same doc, ones that match the document
  377.   //
  378.   int tplCount = 0;
  379.   for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate()) {
  380.     if (tpl->IsVisible() && !tpl->IsFlagSet(dtReadOnly)
  381.                          && (!sameDoc || tpl->IsMyKindOfDoc(doc))) {
  382.       if (tplList) {
  383.         CHECK(tplCount < size);
  384.         tplList[tplCount] = tpl;
  385.       }
  386.       tplCount++;
  387.     }
  388.   }
  389.   return tplCount;
  390. }
  391.  
  392. //
  393. // Build a list of templates for creating views. Return the number of
  394. // templates in the list.
  395. // NOTE: To find out ahead of time how many templates match a particular
  396. //       document type, use 'GetTemplateCount(docType);'
  397. //
  398. #if __DEBUG < 2
  399. int
  400. TDocManager::GetViewTemplates(TDocTemplate** tplList, int,
  401.                               TDocument& doc)
  402. #else
  403. int
  404. TDocManager::GetViewTemplates(TDocTemplate** tplList, int size,
  405.                               TDocument& doc)
  406. #endif
  407. {
  408.   // Check for no registered templates
  409.   //
  410.   if (!TemplateList) {
  411.     TRACEX(OwlDocView, 0, "GetViewTemplates(): No registered templates!");
  412.     return 0;
  413.   }
  414.  
  415.   // Grab a list of templates for creating views
  416.   //
  417.   int tplCount = 0;
  418.   for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate()) {
  419.     if (tpl->IsMyKindOfDoc(doc)) {
  420.  
  421.       // Don't grab the same view more than once
  422.       //
  423.       const char far* viewName = tpl->GetViewName();
  424.       int index;
  425.       for (index = 0; index < tplCount; index++) {
  426.         if (tplList[index]->GetViewName() == viewName)
  427.           break;
  428.       }
  429.  
  430.       // Skip a view if the document already has one and the template
  431.       // specifies 'SingleView'.
  432.       //
  433.       if (tpl->IsFlagSet(dtSingleView)) {
  434.         TView* pview = 0;
  435.         while ((pview = doc.NextView(pview)) != 0)
  436.           if (tpl->IsMyKindOfView(*pview))
  437.             index = -1;
  438.       }
  439.  
  440.       // Store the template if we have a match...
  441.       //
  442.       if (index == tplCount) {
  443.  
  444.         CHECK(tplList);
  445.         CHECK(tplCount < size);
  446.  
  447.         tplList[tplCount++] = tpl;
  448.       }
  449.     }
  450.   }
  451.   return tplCount;
  452. }
  453.  
  454. //
  455. // Build up a long string containing the template descriptions and file filters
  456. // for every template in the given list. Return the length of the buffer
  457. // needed. Passing 0 for buffer skips actual buffer writing. String will be
  458. // in the form:
  459. //
  460. //   "<descr1> (<filter1>)|(<filter1>)|<descr2> (<filter2>)|(<filter2>)|"
  461. //
  462. int
  463. TDocManager::GetTemplateDescription(TDocTemplate** tpllist, int tplcount,
  464.                                     char* buffer, int size)
  465. {
  466.  
  467.   int len = 0;
  468.  
  469.   // If buffer is 0, then simply compute the length the template description(s)
  470.   // and filter(s)
  471.   //
  472.   if (!buffer) {
  473.     for (int count=0; count < tplcount; count++) {
  474.       TDocTemplate* tpl = tpllist[count];
  475.       CHECK(tpl);
  476.  
  477.       const char far* p = tpl->GetDescription();
  478.       int descLen = (p && *p) ? strlen(p) : 0;
  479.  
  480.       p = tpl->GetFileFilter();
  481.       int fltrLen = (p && *p) ? strlen(p) : 0;
  482.  
  483.       // Description + " (" + filter  + ") " + filter  +"|"
  484.       //
  485.       len += (descLen  +  2 + fltrLen +  2   + fltrLen + 1);
  486.     }
  487.   }
  488.   else {
  489.  
  490.     // Check that buffer is big enough
  491.     //
  492.     CHECK(GetTemplateDescription(tpllist, tplcount) < size);
  493.  
  494.     // Put together a string of description and filters
  495.     //
  496.     buffer[0] = 0;
  497.     for (int count = 0; count < tplcount; count++ ) {
  498.       TDocTemplate* tpl = tpllist[count];
  499.       CHECK(tpl);
  500.  
  501.       const char far* p = tpl->GetDescription();
  502.       if (p && *p)
  503.         strcat(buffer, p);
  504.  
  505.       p = tpl->GetFileFilter();
  506.       if (p && *p) {
  507.         strcat(buffer, " (");
  508.         strcat(buffer, p);
  509.         strcat(buffer, ")|");
  510.         strcat(buffer, p);
  511.       }
  512.       strcat(buffer, "|");
  513.     }
  514.     len = strlen(buffer);
  515.   }
  516.  
  517.   return len;
  518. }
  519.  
  520. //----------------------------------------------------------------------------
  521.  
  522. //
  523. // Create any kind of document, using the supplied path. Prompt user to select
  524. // from the list of non-hidden doc templates.
  525. //
  526. TDocument*
  527. TDocManager::CreateAnyDoc(const char far* path, long flags)
  528. {
  529.   // Are we creating a new document?
  530.   //
  531.   bool  newDoc = (flags & dtNewDoc) ? true : false;
  532.  
  533.   // Get a count and list of templates
  534.   //
  535.   int tplcount = GetNewTemplates(0, 0, newDoc);
  536.  
  537.   // Return of there are no usable templates
  538.   //
  539.   if (!tplcount) {
  540.     TRACEX(OwlDocView, 0, "No usable templates found in CreateAnyDoc()");
  541.     return 0;
  542.   }
  543.  
  544.   // Allocate memory and get templates
  545.   //
  546.   TDocTemplatePtr* tpllist = new TDocTemplatePtr[tplcount];
  547.   TAPointer<TDocTemplatePtr> _clnObj(tpllist);
  548.   GetNewTemplates(tpllist, tplcount, newDoc);
  549.  
  550.   char filepath[_MAX_PATH];
  551.   filepath[0] = 0;
  552.  
  553.   // Find the index of the template to be used
  554.   //
  555.   int index;
  556.   if (newDoc) {
  557.  
  558.     // If there's only one template, use it - otherwise prompt user
  559.     // to select the document type
  560.     //
  561.     if (tplcount == 1)
  562.       index = 1;
  563.     else
  564.       index = SelectDocType(tpllist, tplcount);
  565.   }
  566.   else {
  567.  
  568.     // Select the doctemplate using the doc template filters
  569.     //
  570.     if (path)
  571.       strcpy(filepath, path);
  572.     else
  573.       filepath[0] = 0;
  574.  
  575.     index = SelectDocPath(tpllist, tplcount, filepath, sizeof filepath, flags);
  576.  
  577.     WARNX(OwlDocView, index > tplcount, 0,
  578.           "Invalid template index from SelectDocPath");
  579.   }
  580.  
  581.   // No index implies user cancelled or error
  582.   //
  583.   if (!index)
  584.     return 0;
  585.  
  586.   // If opening a document, check that document is not already opened
  587.   //
  588.   if (filepath[0]) {
  589.     TDocument* doc = FindDocument(filepath);
  590.     if (doc != 0) {
  591.       PostDocError(*doc, IDS_DUPLICATEDOC);
  592.       return 0;
  593.     }
  594.   }
  595.  
  596.   // We have a template, now create the document & return it if successful
  597.   //
  598.   return CreateDoc(tpllist[index-1], filepath, 0, flags);
  599. }
  600.  
  601. //
  602. // Create a document using a specific doc template, then if successful,
  603. // initialize the document using InitDoc()
  604. //
  605. TDocument*
  606. TDocManager::CreateDoc(TDocTemplate* tpl, const char far* path,
  607.                        TDocument* parent, long flags)
  608. {
  609.   if (!tpl) {
  610.     TRACEX(OwlDocView, 0, "CreateDoc(): NULL template specified!");
  611.     return 0;
  612.   }
  613.  
  614.   // Creation step 0: Inform docmanager that we're about to create a document
  615.   // and allow docmanager to veto
  616.   //
  617.   if (!CreatingDoc(tpl)) {
  618.     TRACEX(OwlDocView, 1, "CreateDoc(): Creation vetoed.");
  619.     return 0;
  620.   }
  621.  
  622.   // Creation step 1: Construct the document, passing in the parent document
  623.   // Put together a dummy parent document if no parent doc was specified in
  624.   // order to allow us to pass in the DocManager pointer hidden in the parent
  625.   // doc
  626.   //
  627.   TDocument* doc;
  628.   if (!parent)
  629.     doc = tpl->ConstructDoc(&TDocument(this));
  630.   else
  631.     doc = tpl->ConstructDoc(parent);
  632.  
  633.   if (!doc) {
  634.     TRACEX(OwlDocView, 0, "CreateDoc(): ConstructDoc call failed" );
  635.     return 0;
  636.   }
  637.  
  638.   // Creation step2: Initialize the document
  639.   //
  640.   doc->SetTemplate(tpl);
  641.   return InitDoc(doc, path, flags);
  642. }
  643.  
  644. //
  645. // Initialize document using its specific doc template
  646. // Prompts for pathname using SelectDocPath() if no path is supplied and not
  647. // creating a new document
  648. //
  649. // NOTE: Will delete the passed document if unable to properly initialized doc
  650. //       or if unable to create the view & dtAutoDelete is set.
  651. //
  652. TDocument*
  653. TDocManager::InitDoc(TDocument* doc, const char far* path, long flags)
  654. {
  655.   PRECONDITION(doc);
  656.  
  657.   TDocTemplate* tpl = doc->GetTemplate();
  658.   if (!tpl) {
  659.     TRACEX(OwlDocView, 0, "TDocManager::InitDoc(), doc has not template");
  660.     return 0;
  661.   }
  662.  
  663.   // Alter flags with template's flags
  664.   //
  665.   flags ^= tpl->GetFlags();
  666.  
  667.   // Initialize new document
  668.   //
  669.   if (flags & dtNewDoc) {
  670.     doc->SetDocPath(0);
  671.  
  672.     // Allow document to initialize and cleanup if unsuccessful
  673.     //
  674.     if (!doc->InitDoc()){
  675.       PostDocError(*doc, IDS_UNABLEOPEN);
  676.       delete doc;
  677.       return 0;
  678.     }
  679.   }
  680.   else {
  681.     if (!path) {
  682.  
  683.       if (!tpl->GetFileFilter())
  684.         return 0;
  685.  
  686.       // Prompt user for document's path
  687.       //
  688.       char filepath[_MAX_PATH];
  689.       filepath[0] = 0;
  690.       int index = SelectDocPath(&tpl, 1, filepath, sizeof filepath, flags);
  691.  
  692.       // if user cancelled UI, cleanup document
  693.       //
  694.       if (!index) {
  695.         delete doc;
  696.         return 0;
  697.       }
  698.  
  699.       path = filepath;
  700.     }
  701.  
  702.     // Update document's path
  703.     //
  704.     doc->SetDocPath(path);
  705.  
  706.     // Allow document to initialize and cleanup if unsuccessful
  707.     //
  708.     if (!doc->InitDoc()) {
  709.       PostDocError(*doc, IDS_UNABLEOPEN);
  710.       delete doc;
  711.       return 0;
  712.     }
  713.  
  714.     // Attempt to open document if 'dtAutoOpen' is enabled. Cleanup if
  715.     // unsuccessful.
  716.     //
  717.     if (flags & dtAutoOpen) {
  718.       if (!doc->Open((flags & dtNoReadOnly) ? ofReadWrite : ofRead)) {
  719.         PostDocError(*doc, IDS_UNABLEOPEN);
  720.         delete doc;
  721.         return 0;
  722.       }
  723.     }
  724.   }
  725.  
  726.   // Post event that document has been created
  727.   //
  728.   PostEvent(dnCreate, *doc);
  729.  
  730.   // Create a view unless 'dtNoAutoView' flag is set. Cleanup on failure if
  731.   // dtAutoDelete is set on behalf of the view.
  732.   //
  733.   if (!(flags & dtNoAutoView)) {
  734.     if (!CreateView(*doc)) {
  735.       if (flags & dtAutoDelete) {
  736.         if (doc->IsOpen())
  737.           doc->Close();
  738.         delete doc;
  739.       }
  740.       return 0;
  741.     }
  742.   }
  743.   return doc;
  744. }
  745.  
  746. //
  747. // Create (Construct and Init) a view from registered templates supporting
  748. // a given doc.
  749. //
  750. // This implementation allows user intervention if there is more than one
  751. // template available, by calling SelectViewType()
  752. //
  753. TView*
  754. TDocManager::CreateAnyView(TDocument& doc, long /*flags*/)
  755. {
  756.   int tplCount = GetTemplateCount(&doc);
  757.  
  758.   // Abort if there are no usable templates
  759.   //
  760.   if (!tplCount) {
  761.     WARNX(OwlDocView, !tplCount, 0, "CreateAnyView(): no usable template");
  762.     return 0;
  763.   }
  764.  
  765.   // Allocate memory for templates and get 'em
  766.   //
  767.   TDocTemplatePtr* tplList = new TDocTemplatePtr[tplCount];
  768.   TAPointer<TDocTemplatePtr> _clnObj(tplList);
  769.   tplCount = GetViewTemplates(tplList, tplCount, doc);
  770.  
  771.   int index;
  772.   if (tplCount > 1)
  773.     index = SelectViewType(tplList, tplCount);
  774.   else
  775.     index = tplCount;
  776.  
  777.   if (index <= 0) {
  778.     WARNX(OwlDocView, !tplCount, 0, "CreateAnyView(): no usable template");
  779.     WARNX(OwlDocView, tplCount,  0, "CreateAnyView(): invalid template index");
  780.     return 0;
  781.   }
  782.  
  783.   CHECK(index > 0);
  784.   CHECK(index < tplCount);
  785.  
  786.   // Now create the view on the document using the selected template
  787.   //
  788.   return CreateView(doc, tplList[index-1]);
  789. }
  790.  
  791. //
  792. // Create a view on a given document using the given tempalte, or document's
  793. // template if none given, and then initialize the view. Return the view if
  794. // all was OK, or 0 if something failed.
  795. //
  796. TView*
  797. TDocManager::CreateView(TDocument& doc, TDocTemplate* tpl)
  798. {
  799.   // Default to the document's template if none provided
  800.   //
  801.   if (!tpl)
  802.     tpl = doc.GetTemplate();
  803.   CHECK(tpl);
  804.  
  805.   TView* view = tpl->ConstructView(doc);
  806.   WARNX(OwlDocView, !view, 0, "CreateView(): ConstructView call failed");
  807.  
  808.   view = doc.InitView(view);
  809.   WARNX(OwlDocView, !view, 0, "CreateView(): InitView call failed");
  810.  
  811.   return view;
  812. }
  813.  
  814. //----------------------------------------------------------------------------
  815.  
  816. //
  817. // Displays FileSave dialog prompting for a filename for saving a document.
  818. //
  819. bool
  820. TDocManager::SelectSave(TDocument& doc)
  821. {
  822.   TDocTemplate* tpl = doc.GetTemplate();
  823.  
  824.   if (!tpl || !tpl->GetFileFilter())
  825.     return false;
  826.  
  827.   char filepath[_MAX_PATH];
  828.   if (doc.GetDocPath())
  829.     strcpy(filepath, doc.GetDocPath());
  830.   else
  831.     filepath[0] = 0;    // no initial file path
  832.  
  833.   int index = SelectDocPath(&tpl, 1, filepath, sizeof filepath, 0, true, &doc);
  834.   return index ? doc.SetDocPath(filepath) : false;
  835. }
  836.  
  837. //
  838. // Select a new docpath for a document from the registered templates
  839. // supporting the doc.
  840. //
  841. TDocTemplate*
  842. TDocManager::SelectAnySave(TDocument& doc, bool samedoc)
  843. {
  844.   int tplcount = GetSaveTemplates(0, 0, doc, samedoc);
  845.  
  846.   // Abort if there are no usable templates
  847.   //
  848.   if (!tplcount) {
  849.     WARNX(OwlDocView, !tplcount, 0, "SelectAnySave(): no usable templates");
  850.     return 0;
  851.   }
  852.  
  853.   // Allocate memory for templates and get 'em
  854.   //
  855.   TDocTemplatePtr* tpllist = new TDocTemplatePtr[tplcount];
  856.   TAPointer<TDocTemplatePtr> _clnObj(tpllist);
  857.   GetSaveTemplates(tpllist, tplcount, doc, samedoc);
  858.  
  859.   // Grab the file name, if there's one
  860.   //
  861.   char filepath[_MAX_PATH];
  862.   if (doc.GetDocPath())
  863.     strcpy(filepath, doc.GetDocPath());
  864.   else
  865.     filepath[0] = 0;
  866.  
  867.   // Allow UI for user input
  868.   //
  869.   int index;
  870.   index = SelectDocPath(tpllist, tplcount, filepath, sizeof filepath, 0, true, &doc);
  871.   if (!index)
  872.     return 0;
  873.  
  874.   CHECK(index >= 1);
  875.   CHECK(index <= tplcount);
  876.  
  877.   // Perform save by setting the new path into the doc
  878.   //
  879.   if (!doc.SetDocPath(filepath))
  880.     return 0;
  881.  
  882.   return tpllist[index-1];
  883. }
  884.  
  885. //
  886. // Method invoked when specified document is about to be closed.
  887. // Returns 'true' if DocManager should proceed with the closing
  888. // stages of the document, or 'false' otherwise.
  889. //
  890. bool
  891. TDocManager::FlushDoc(TDocument& doc)
  892. {
  893.   while (doc.IsDirty()) {
  894.     int saveOrNot = doc.IsEmbedded() ?
  895.                       IDYES :
  896.                       PostDocError(doc, IDS_DOCCHANGED, MB_YESNOCANCEL);
  897.  
  898.     switch (saveOrNot) {
  899.       case IDYES:
  900.         // Prompt the user for filename in save-as situation
  901.         //
  902.         if (!doc.IsEmbedded() && doc.GetDocPath() == 0) {
  903.  
  904. #if defined(OLD_DOCVIEW)
  905.           TDocTemplate* tpl = SelectAnySave(doc, false);
  906. #else
  907.           TDocTemplate* tpl = SelectAnySave(doc, true);
  908. #endif
  909.           if (!tpl)
  910.             continue;
  911.  
  912.           //
  913.           if (tpl != doc.Template)
  914.             doc.SetTemplate(tpl);
  915.         }
  916.         if (doc.Commit())
  917.           return true;
  918.         continue;
  919.  
  920.       case IDNO:
  921.         if (doc.Revert(true))
  922.           return true;
  923.         return false;
  924.  
  925.       case IDCANCEL:
  926.         return false;
  927.     }
  928.   }
  929.   return true;
  930. }
  931.  
  932. //----------------------------------------------------------------------------
  933.  
  934. //
  935. // Return a matching template given a document path.
  936. //
  937. // This implementation compares the path's extension with the ';' separated
  938. // filter lists in each template looking for a case-insensitive match. Allows
  939. // '?'s in the template filters to match any character in the path's extension
  940. //
  941. // Example:
  942. //   The path: "documents.1995\accounts_receivable.plan"
  943. //   Would match the filter: "*.xls;*.wk?;*.plan"
  944. //
  945. TDocTemplate*
  946. TDocManager::MatchTemplate(const char far* path)
  947. {
  948.  
  949.   // Iterate through templates
  950.   //
  951.   for (TDocTemplate* tpl = TemplateList; tpl != 0; tpl = tpl->GetNextTemplate()) {
  952.  
  953.     // Skip hidden templates or templates without filters specified
  954.     //
  955.     const char far* tplFilter = tpl->GetFileFilter();
  956.     if (!tplFilter || tpl->IsFlagSet(dtHidden))
  957.       continue;
  958.  
  959.     // Make locale copy of filter
  960.     //
  961.     TAPointer<char> fltrCopy = nstrnewdup(tplFilter);
  962.     char far* fltr = fltrCopy;
  963.     char far* nxtFltr;
  964.  
  965.     // For each template, try each wilcard specified
  966.     //
  967.     while (fltr) {      
  968.  
  969.       // Is there another wildcard following - Null terminate at ';'
  970.       //
  971.       nxtFltr = strchr(fltr, ';');
  972.       if (nxtFltr)
  973.         *nxtFltr++ = 0;
  974.  
  975.       if (IsAMatch(path, fltr))
  976.         return tpl;
  977.  
  978.       // Try next filter
  979.       //
  980.       fltr = (nxtFltr && *nxtFltr) ? nxtFltr : 0;
  981.     } 
  982.   }
  983.   return 0;
  984. }
  985.  
  986. //
  987. // Internal routine used to match a portion of a filename (i.e. name or
  988. // extension) to a wilcard pattern.
  989. //
  990. static bool 
  991. nameMatch(const char* name, const char* wc)
  992. {
  993.   while (true) {
  994.     if (*wc == '*' || (!*wc && !*name))
  995.       return true;
  996.     if ((*wc == '?' && *name) || (toupper(*name) == toupper(*wc))) {
  997.       wc++; 
  998.       name++;      
  999.       continue;
  1000.     }
  1001.     break;
  1002.   }
  1003.   return false;
  1004. }
  1005.  
  1006. //
  1007. // Helper method used by 'MatchTemplate' to determine whether a filename
  1008. // fits the pattern [wilcard] described by a filter.
  1009. //
  1010. bool
  1011. TDocManager::IsAMatch(const char far* path, const char far* fltr)
  1012. {
  1013.   PRECONDITION(path);
  1014.   PRECONDITION(fltr);
  1015.  
  1016.   // Ensure path has at least a valid file name
  1017.   //
  1018.   TFileName fname(path);
  1019.   if (!fname.HasParts(TFileName::File)) {
  1020.     TRACEX(OwlDocView, 0, "IsAMatch: Invoked with invalid path");
  1021.     return false;
  1022.   }
  1023.  
  1024.   // Retrieve name/extension from path
  1025.   //
  1026.   string name = fname.GetParts(TFileName::File);
  1027.   string ext  = fname.GetParts(TFileName::Ext);
  1028.   
  1029.   // Get pointers to path's name and extension
  1030.   //
  1031.   const char* ppn = name.c_str();
  1032.   const char* ppe = fname.HasParts(TFileName::Ext) ? ext.c_str() : 0;
  1033.   if (*ppe == '.')
  1034.     ppe++;
  1035.  
  1036.   // Get pointers to filter's name and extension
  1037.   //
  1038.   TAPointer<char> filter = nstrnewdup(fltr);
  1039.   char* pfn = filter;
  1040.   char* pfe = strrchr(filter, '.');
  1041.  
  1042.   // Skip past '.' separator of filter
  1043.   //
  1044.   if (pfe) 
  1045.     *pfe++ = 0;
  1046.  
  1047.   // Match the name and extension
  1048.   //
  1049.   return nameMatch(ppn, pfn) && nameMatch(ppe, pfe);
  1050. }
  1051.  
  1052. //
  1053. // Return the document which is 'current'. This is based on which visible view
  1054. // has user focus.
  1055. //
  1056. TDocument*
  1057. TDocManager::GetCurrentDoc()
  1058. {
  1059.   PRECONDITION(GetApplication());
  1060.   PRECONDITION(GetApplication()->GetMainWindow());
  1061.  
  1062.   HWND hWnd = GetApplication()->GetMainWindow()->GetCommandTarget();
  1063.   TDocument* doc = 0;
  1064.  
  1065. #if defined(OLD_DOCVIEW)
  1066.  
  1067.   if (hWnd && ::IsWindow(hWnd)) {
  1068.     while ((doc = DocList.Next(doc)) != 0 && !doc->HasFocus(hWnd))
  1069.       ;
  1070.   }
  1071.  
  1072. #else
  1073.   if (hWnd && ::IsWindow(hWnd)) {
  1074.     while ((doc = DocList.Next(doc)) != 0 ) {
  1075.       TDocument* childDoc = doc->DocWithFocus(hWnd);
  1076.       if (childDoc) {
  1077.         doc = childDoc;
  1078.         break;
  1079.       }
  1080.     }
  1081.   }
  1082. #endif
  1083.   return doc;
  1084. }
  1085.  
  1086. //
  1087. // Returns a pointer to the TDocument object if the specified document
  1088. // is currently opened and manager by the DocManager. Returns 0 otherwise.
  1089. //
  1090. TDocument*
  1091. TDocManager::FindDocument(const char far* path)
  1092. {
  1093.   TDocument* doc = 0;
  1094.   while ((doc = DocList.Next(doc)) != 0)
  1095.     if (path) {
  1096.       if (doc->GetDocPath() && strcmp(doc->GetDocPath(), path) == 0)
  1097.         break;
  1098.     }
  1099.     else {
  1100.       if (doc->GetDocPath() == 0)
  1101.         break;
  1102.     }
  1103.   return doc;
  1104. }
  1105.  
  1106. //----------------------------------------------------------------------------
  1107.  
  1108. //
  1109. // Adds a template to the template list managed by the DocManager.
  1110. //
  1111. void
  1112. TDocManager::AttachTemplate(TDocTemplate& tpl)
  1113. {
  1114.   tpl.SetDocManager(this);
  1115.   TDocTemplate::AddLink((TRegLink*&)TemplateList, tpl);
  1116. }
  1117.  
  1118. //
  1119. // Removes a template from the list of templates currently managed by
  1120. // the DocManager.
  1121. //
  1122. void
  1123. TDocManager::DeleteTemplate(TDocTemplate& tpl)
  1124. {
  1125.   // Skip static templates
  1126.   //
  1127.   if (tpl.IsStatic()) {
  1128.     TRACEX(OwlDocView, 0, "TDocManager::DeleteTemplate() invoked for static");
  1129.     return;
  1130.   }
  1131.  
  1132.   // Check if it has an owner
  1133.   //
  1134.   if (!tpl.GetDocManager()) {
  1135.     TRACEX(OwlDocView, 0, "TDocManager::DeleteTemplate(), templ. has no owner");
  1136.     return;
  1137.   }
  1138.  
  1139.   // Unreference the template - will be deleted unless documents
  1140.   // still reference template.
  1141.   //
  1142.   if (TDocTemplate::RemoveLink((TRegLink*&)TemplateList, tpl)) {
  1143.     UnRefTemplate(tpl);
  1144.     return;
  1145.   }
  1146.  
  1147.   TRACEX(OwlDocView, 0, "TDocManager::DeleteTemplate(), not in app list");
  1148. }
  1149.  
  1150. //----------------------------------------------------------------------------
  1151.  
  1152. //
  1153. // Displays a MessageBox about a document-related error. Returns an integer
  1154. // identifying the MessageBox option (push-button) selected by the user.
  1155. //
  1156. uint
  1157. TDocManager::PostDocError(TDocument& doc, uint sid, uint choice)
  1158. {
  1159.   PRECONDITION(GetApplication());
  1160.   PRECONDITION(GetApplication()->GetMainWindow());
  1161.  
  1162.   char buf[256];
  1163.   if (GetApplication()->LoadString(sid, buf, sizeof buf) == 0)
  1164.     sprintf(buf, "Error: Message [string ID %u] not found", sid);
  1165.   if (choice != MB_OK)
  1166.     choice |= MB_ICONQUESTION;
  1167.   return GetApplication()->GetMainWindow()->MessageBox(buf, doc.GetTitle(), choice);
  1168. }
  1169.  
  1170. //
  1171. // Post a OWL-defined message regarding an event [identified by the 'id'
  1172. // parameter] related to the specified document ('doc').
  1173. //
  1174. void
  1175. TDocManager::PostEvent(int id, TDocument& doc)
  1176. {
  1177.   TWindow* win = GetApplication()->GetMainWindow();
  1178.   if (win && win->GetHandle())
  1179.     win->SendMessage(WM_OWLDOCUMENT, id, TParam2(&doc));
  1180. }
  1181.  
  1182. //
  1183. // Post a OWL-defined message regarding an event [identified by the 'id'
  1184. // parameter] related to the specified view ('view').
  1185. //
  1186. void
  1187. TDocManager::PostEvent(int id, TView& view)
  1188. {
  1189.   TWindow* win = GetApplication()->GetMainWindow();
  1190.   if (win && win->GetHandle())
  1191.     win->SendMessage(WM_OWLVIEW, id, TParam2(&view));
  1192. }
  1193.  
  1194. //----------------------------------------------------------------------------
  1195.  
  1196. //
  1197. // Given a list of templates, prompt user to select a document class for a
  1198. // new document,
  1199. // Return the template index used for the selection (1-based), 0 if failure
  1200. //
  1201. int
  1202. TDocManager::SelectDocType(TDocTemplate** tpllist, int tplcount)
  1203. {
  1204.   TPickListPopup pickl(GetApplication()->GetMainWindow(), IDS_DOCLIST);
  1205.   while (tplcount--) {
  1206.     CHECK(*tpllist);
  1207.     pickl.AddString((*tpllist++)->GetDescription());
  1208.   }
  1209.   int index = pickl.Execute() + 1;
  1210.   if (index == -1)
  1211.     return 0;
  1212.   return index;
  1213. //  return pickl.Execute() + 1;
  1214. }
  1215.  
  1216. //
  1217. // Given a list of templates, prompt user with one or all templates to select
  1218. // file to open
  1219. // Returns the template index used for the selection (1-based), 0 if failure
  1220. //
  1221. // This is Windows-specific, using the system-provided file open dialog box
  1222. //
  1223. int
  1224. TDocManager::SelectDocPath(TDocTemplate** tpllist, int tplcount,
  1225.                            char far* path, int buflen, long flags,
  1226.                            bool save, TDocument* doc)
  1227. {
  1228.   // Compute length of description(s) and filter(s)
  1229.   //
  1230.   int len = GetTemplateDescription(tpllist, tplcount);
  1231.  
  1232.   // Put together a string of description and filters
  1233.   //
  1234.   TAPointer<char> filtbuf = new char[++len];
  1235.   GetTemplateDescription(tpllist, tplcount, filtbuf, len);
  1236.  
  1237.   // Find the (default) template to select
  1238.   //
  1239.   int index, count;
  1240.   TDocument* curDoc = save ? (doc ? doc : GetCurrentDoc()) : 0;
  1241.   CHECK(!save || curDoc);
  1242.   if (save) {
  1243.     for (index = count = 0; count < tplcount; count++) {
  1244.       if (tpllist[count] == curDoc->GetTemplate()) {
  1245.         index = count;
  1246.         break;
  1247.       }
  1248.     }
  1249.   }
  1250.   else {
  1251.     for (index = count = 0; count < tplcount; count++) {
  1252.       if (tpllist[count]->IsFlagSet(dtSelected)) {
  1253.         index = count;
  1254.         break;
  1255.       }
  1256.     }
  1257.   }
  1258.  
  1259.   // Initialize data structure used for launching Common Dialog
  1260.   //
  1261.   flags = (tpllist[index]->GetFlags() | flags) & ~dtProhibited;
  1262.   TDvOpenSaveData data(flags,                           // flags
  1263.                        filtbuf,                         // filter
  1264.      CONST_CAST(char*, tpllist[index]->GetDirectory()), // initDir.
  1265.      CONST_CAST(char*, tpllist[index]->GetDefaultExt()),// defExt.
  1266.                        index ? index+1 : 0,             // filterIndex
  1267.                        tpllist,                         // template list
  1268.                        tplcount);                       // template count
  1269.   // Execute dialog
  1270.   //
  1271.   int result;
  1272.   TWindow* parent = GetApplication()->GetMainWindow();
  1273.   if (save)
  1274.     result = TDvFileSaveDialog(parent, data).Execute();
  1275.   else
  1276.     result = TDvFileOpenDialog(parent, data).Execute();
  1277.  
  1278.   // Dialog was cancelled!
  1279.   //
  1280.   if (result != IDOK) {
  1281.     WARNX(OwlDocView, data.Error != 0, 0, "Common dialog error: " << \
  1282.                       data.Error << " in SelectDocPath()" );
  1283.     return 0;
  1284.   }
  1285.  
  1286.   // Here, there's a major dilemma! How, do we know the user did not
  1287.   // mislead us? For example, the user may have selected the *wrong*
  1288.   // template for saving a particular document... This is crucial when
  1289.   // saving documents!!!
  1290.   //
  1291.  
  1292.   // Update templates to 'remember' the template last used
  1293.   //
  1294.   for (count = 0; count < tplcount; count++) {
  1295.     if (count == index-1)
  1296.       tpllist[count]->SetFlag(dtSelected);
  1297.     else
  1298.       tpllist[count]->ClearFlag(dtSelected);
  1299.   }
  1300.  
  1301.   // Update selected template with directory
  1302.   // 
  1303.  
  1304.  
  1305.   // Copy file name over
  1306.   //
  1307.   CHECK(path);
  1308.   if (data.FileName && data.FileName[0]) {
  1309.     WARNX(OwlDocView, strlen(data.FileName) < buflen, 0,
  1310.           "SelectDocPath: Specified buffer is too small");
  1311.     strncpy(path, data.FileName, buflen);
  1312.   }
  1313.   else
  1314.     *path = 0;
  1315.  
  1316.   // Return index [1-based] of selected template
  1317.   //
  1318.   CHECK(data.FilterIndex >= 1);
  1319.   CHECK(data.FilterIndex <= tplcount);
  1320.   return data.FilterIndex;
  1321. }
  1322.  
  1323. //
  1324. // Given a list of templates, prompt user to select a view class for a new
  1325. // view on an existing document.
  1326. // Return the template index used for the selection (1-based), 0 if failure
  1327. //
  1328. int
  1329. TDocManager::SelectViewType(TDocTemplate** tpllist, int tplcount)
  1330. {
  1331.   TPickListPopup pickl(GetApplication()->GetMainWindow(), IDS_VIEWLIST);
  1332.   while (tplcount--) {
  1333.     CHECK(*tpllist);
  1334.     pickl.AddString((*tpllist++)->GetViewName());
  1335.   }
  1336.   return pickl.Execute() + 1;
  1337. }
  1338.  
  1339. //
  1340. // This method is invoked just before the DocumentManager creates a new
  1341. // document. The default behaviour is to close and delete the current
  1342. // document if we're in SDI mode.
  1343. //
  1344. bool
  1345. TDocManager::CreatingDoc(TDocTemplate* /*tpl*/)
  1346. {
  1347.   if (Mode & dmSDI) {
  1348.     TDocument* doc = DocList.Next(0);
  1349.     if (doc) {
  1350.       if (!doc->CanClose())
  1351.         return false;
  1352.       if (!doc->Close()) {
  1353.         PostDocError(*doc, IDS_UNABLECLOSE);
  1354.         return false;
  1355.       }
  1356.       delete doc;
  1357.     }
  1358.   }
  1359.   return true;
  1360. }
  1361.  
  1362. //
  1363. // Upate the specified menu bar by removing the current '&File' popup
  1364. // menu [assumed to be the first popup of the menubar] and replacing it
  1365. // with the ObjectWindows' standard File popup menu resource.
  1366. //
  1367. void
  1368. TDocManager::UpdateFileMenu(TMenu& menubar)
  1369. {
  1370.   PRECONDITION(GetApplication());
  1371.   PRECONDITION(::Module);
  1372.  
  1373.   HMENU hMenu = GetApplication()->LoadMenu(IDM_DOCMANAGERFILE);
  1374.   if (!hMenu)
  1375.     hMenu = ::Module->LoadMenu(IDM_DOCMANAGERFILE);
  1376.   if (hMenu) {
  1377.     char menuTitle[40];
  1378.     GetApplication()->LoadString(IDS_DOCMANAGERFILE, menuTitle, sizeof menuTitle);
  1379.  
  1380.     TMenu filePopup(hMenu);
  1381.     if (Mode & dmNoRevert)
  1382.       filePopup.DeleteMenu(CM_FILEREVERT, MF_BYCOMMAND);
  1383.  
  1384.     // Assumes '&File' popup is first entry of menubar...
  1385.     //
  1386.     menubar.DeleteMenu(0, MF_BYPOSITION);
  1387.     menubar.InsertMenu(0, MF_BYPOSITION|MF_POPUP, (uint)hMenu, menuTitle);
  1388.   }
  1389.   WARNX(OwlDocView, !hMenu, 0, "Cannot load DocManager's File Menu");
  1390. }
  1391.  
  1392. //----------------------------------------------------------------------------
  1393.  
  1394. //
  1395. //
  1396. //
  1397. bool
  1398. TDocManager::EvCanClose()
  1399. {
  1400.   TDocument* doc = 0;
  1401.   while ((doc = DocList.Next(doc)) != 0) {
  1402.     if (!doc->CanClose())  // normally calls back to FlushDoc()
  1403.       return false;
  1404.   }
  1405.   return true;
  1406. }
  1407.  
  1408. //
  1409. // Preprocess the app frame's menu to replace the file menu with one managed
  1410. // by this docmanager
  1411. //
  1412. void
  1413. TDocManager::EvPreProcessMenu(HMENU hMenuBar)
  1414. {
  1415.   if (Mode & dmMenu)
  1416.     UpdateFileMenu(TMenu(hMenuBar));
  1417. }
  1418.  
  1419. //
  1420. //
  1421. //
  1422. void
  1423. TDocManager::EvWakeUp()
  1424. {
  1425.   TDocument* doc = 0;
  1426.   while ((doc = DocList.Next(doc)) != 0)
  1427.     doc->ReindexFrames();
  1428. }
  1429.  
  1430. //----------------------------------------------------------------------------
  1431. // Command event handlers
  1432. //
  1433.  
  1434. //
  1435. //
  1436. //
  1437. void
  1438. TDocManager::CeFileNew(TCommandEnabler& ce)
  1439. {
  1440.   ce.Enable(TemplateList != 0);
  1441. }
  1442.  
  1443. //
  1444. //
  1445. //
  1446. void
  1447. TDocManager::CmFileNew()
  1448. {
  1449.   CreateAnyDoc(0, dtNewDoc);
  1450. }
  1451.  
  1452. //
  1453. //
  1454. //
  1455. void
  1456. TDocManager::CeFileOpen(TCommandEnabler& ce)
  1457. {
  1458.   ce.Enable(TemplateList != 0);
  1459. }
  1460.  
  1461. //
  1462. //
  1463. //
  1464. void
  1465. TDocManager::CmFileOpen()
  1466. {
  1467.   CreateAnyDoc(0, 0);
  1468. }
  1469.  
  1470. //
  1471. //
  1472. //
  1473. void
  1474. TDocManager::CeFileClose(TCommandEnabler& ce)
  1475. {
  1476.   ce.Enable(GetCurrentDoc() != 0);
  1477. }
  1478.  
  1479. //
  1480. //
  1481. //
  1482. void
  1483. TDocManager::CmFileClose()
  1484. {
  1485.   TDocument* doc = GetCurrentDoc();
  1486.   if (doc && doc->CanClose()) {  // normally calls back to FlushDoc()
  1487.     if (!doc->Close())
  1488.       PostDocError(*doc, IDS_UNABLECLOSE);
  1489.     else
  1490.       delete doc;
  1491.   }
  1492.   WARNX(OwlDocView, !doc, 0, "FileClose invoked with no current doc");
  1493. }
  1494.  
  1495. //
  1496. //
  1497. //
  1498. void
  1499. TDocManager::CeFileSaveAs(TCommandEnabler& ce)
  1500. {
  1501.   TDocument* doc = GetCurrentDoc();
  1502.   ce.Enable(doc != 0);
  1503. }
  1504.  
  1505. //
  1506. //
  1507. //
  1508. void
  1509. TDocManager::CmFileSaveAs()
  1510. {
  1511.   TDocument* doc = GetCurrentDoc();
  1512.   if (doc) {
  1513.     TDocTemplate* tpl = SelectAnySave(*doc, true);
  1514.     if (tpl) {
  1515.       if (tpl != doc->Template)
  1516.         doc->SetTemplate(tpl);       // replace existing template
  1517.       if (doc->Commit(true))         // force rewrite to new path
  1518.         PostEvent(dnRename, *doc);   // notify that doc has been renamed
  1519.     }
  1520.   }
  1521. }
  1522.  
  1523. //
  1524. //
  1525. //
  1526. void
  1527. TDocManager::CeFileSave(TCommandEnabler& ce)
  1528. {
  1529.   TDocument* doc = GetCurrentDoc();
  1530.   ce.Enable(doc && (doc->IsDirty() || (Mode & dmSaveEnable)));
  1531. }
  1532.  
  1533. //
  1534. //
  1535. //
  1536. void
  1537. TDocManager::CmFileSave()
  1538. {
  1539.   TDocument* doc = GetCurrentDoc();
  1540.   if (doc) {
  1541.     if (!doc->GetDocPath()) {
  1542.       CmFileSaveAs();
  1543.       return;
  1544.     }
  1545.     if (!(Mode & dmSaveEnable) && !doc->IsDirty()) {
  1546.       PostDocError(*doc, IDS_NOTCHANGED);
  1547.       return;
  1548.     }
  1549.     doc->Commit();  // No force of write here since is just to same file
  1550.   }
  1551. }
  1552.  
  1553. //
  1554. //
  1555. //
  1556. void
  1557. TDocManager::CeFileRevert(TCommandEnabler& ce)
  1558. {
  1559.   TDocument* doc = GetCurrentDoc();
  1560.   ce.Enable(doc && doc->IsDirty() && doc->GetDocPath());
  1561. }
  1562.  
  1563. //
  1564. //
  1565. //
  1566. void
  1567. TDocManager::CmFileRevert()
  1568. {
  1569.   TDocument* doc = GetCurrentDoc();
  1570.   if (doc && doc->GetDocPath()) {
  1571.     if (!doc->IsDirty()) {
  1572.       PostDocError(*doc, IDS_NOTCHANGED);
  1573.       return;
  1574.     }
  1575.     doc->Revert();
  1576.   }
  1577. }
  1578.  
  1579. //
  1580. //
  1581. //
  1582. void
  1583. TDocManager::CeViewCreate(TCommandEnabler& hndlr)
  1584. {
  1585.   TDocument* doc = GetCurrentDoc();
  1586.   hndlr.Enable(doc != 0);
  1587. }
  1588.  
  1589. //
  1590. //
  1591. //
  1592. void
  1593. TDocManager::CmViewCreate()
  1594. {
  1595.   TDocument* doc = GetCurrentDoc();
  1596.   if (doc)
  1597.     CreateAnyView(*doc);
  1598. }
  1599.  
  1600. #endif  
  1601. //----------------------------------------------------------------------------
  1602. #if !defined(SECTION) || SECTION == 2
  1603.  
  1604. IMPLEMENT_STREAMABLE(TDocManager);
  1605.  
  1606. #if !defined(BI_NO_OBJ_STREAMING)
  1607.  
  1608. //
  1609. //
  1610. //
  1611. void*
  1612. TDocManager::Streamer::Read(ipstream& is, uint32 /*version*/) const
  1613. {
  1614.   TDocManager* o = GetObject();
  1615.  
  1616.   TDocTemplate* tpl = o->TemplateList;
  1617.   for (;;) {
  1618.     int isStatic;
  1619.  
  1620.     is >> isStatic;
  1621.     if (isStatic == -1)
  1622.       break;
  1623.  
  1624.     if (isStatic) {
  1625.       if (tpl) {                         // if static templates available
  1626.         is >> *tpl;                      // update static template data
  1627.         tpl = o->GetNextTemplate(tpl);
  1628.       }
  1629.       else {                            // have run out of static templates
  1630.         char tbuf[sizeof(TDocTemplate)];  // sink for unused template data
  1631.         memset(tbuf, 0, sizeof tbuf);     // force static flag off
  1632.         is >> *(TDocTemplate*)tbuf;
  1633.       }
  1634.     }
  1635.     else {                // if dynamic template, object will be constructed
  1636.       TModule* module;
  1637.       is >> module;
  1638.       is >> tpl;
  1639.       tpl->SetModule(module);
  1640.       o->AttachTemplate(*tpl);
  1641.     }
  1642.   }
  1643.  
  1644.   int count;
  1645.   is >> count;               // document count
  1646.   while (count--) {
  1647.     TDocument*  doc;
  1648.     is >> doc;
  1649.     doc->SetDocManager(*o);  // inserts properly into list
  1650.   }
  1651.  
  1652.   // Get application, & post ourselves a wakeup message to finish things up
  1653.   // once all windows have been created, etc.
  1654.   //
  1655.   o->Application = GetApplicationObject();
  1656.   TWindow* win = o->Application->GetMainWindow();
  1657.   if (win && win->GetHandle())
  1658.     win->PostMessage(WM_OWLWAKEUP);
  1659.  
  1660.   return o;
  1661. }
  1662.  
  1663. //
  1664. //
  1665. //
  1666. void
  1667. TDocManager::Streamer::Write(opstream& os) const
  1668. {
  1669.   TDocManager* o = GetObject();
  1670.  
  1671.   TDocTemplate* tpl = 0;
  1672.   while ((tpl = o->GetNextTemplate(tpl)) != 0) {
  1673.     int flag = tpl->IsStatic();
  1674.     os << flag;
  1675.     if (flag) {
  1676.       os << *tpl;              // write reference to static template
  1677.     }
  1678.     else {
  1679.       os << tpl->GetModule();  // write template's module pointer first
  1680.       os << tpl;               // write pointer to static template
  1681.     }
  1682.   }
  1683.   os << -1;   // template list terminator
  1684.  
  1685.   TDocument* doc = 0;
  1686.   int count;
  1687.   for (count = 0; (doc = o->DocList.Next(doc))!=0; count++) ;
  1688.   os << count;
  1689.  
  1690.   // Must write documents out in order created, i.e. from end of list forward
  1691.   //
  1692.   while (count) {
  1693.     int i = count--;
  1694.     for (doc = 0; i--; doc = o->DocList.Next(doc)) ;
  1695.     os << doc;
  1696.   }
  1697. }
  1698.  
  1699. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  1700.  
  1701. #endif  
  1702. //----------------------------------------------------------------------------
  1703. #if !defined(SECTION) || SECTION == 3
  1704.  
  1705. #if defined(OWL2_COMPAT)
  1706. //
  1707. // TDocTemplate backward compatibility code
  1708. //
  1709.  
  1710. //
  1711. //
  1712. //
  1713. TDocManager::TDocManager(int mode, TDocTemplate*& templateHead)
  1714. {
  1715.   Init(mode, GetApplicationObject(), templateHead);
  1716. }
  1717.  
  1718. //
  1719. //
  1720. //
  1721. bool TDocManager::SelectSave(TDocTemplate* tpl, TDocument& doc)
  1722. {
  1723.   TDocManager* mgr = tpl->GetDocManager();
  1724.   if (!mgr || !tpl || !tpl->GetFileFilter())
  1725.     return false;
  1726.   char filepath[_MAX_PATH];
  1727.   if (doc.GetDocPath())
  1728.     strcpy(filepath, doc.GetDocPath());
  1729.   else
  1730.     filepath[0] = 0;    // no initial file path
  1731.   int index = mgr->SelectDocPath(&tpl, 1, filepath, sizeof filepath, 0, true, &doc);
  1732.   return index ? doc.SetDocPath(filepath) : false;
  1733. }
  1734.  
  1735. //
  1736. //
  1737. //
  1738. TView*
  1739. TDocManager::InitView(TView* view)
  1740. {
  1741.   if (!view) {
  1742.     WARNX(OwlDocView, !view, 0, "InitView(), NULL view specified");
  1743.     return 0;
  1744.   }
  1745.   return view->GetDocument().InitView(view);
  1746. }
  1747.  
  1748. //
  1749. //
  1750. //
  1751. TDocument*
  1752. TDocManager::InitDoc(TDocTemplate& tpl, TDocument* doc,
  1753.                      const char far* path, long flags)
  1754. {
  1755.   TDocManager* mgr = tpl.GetDocManager();
  1756.   if (!mgr || !doc)
  1757.     return 0;
  1758.   doc->SetTemplate(&tpl);
  1759.   return mgr->InitDoc(doc, path, flags);
  1760. }
  1761.  
  1762. //
  1763. //
  1764. //
  1765. void
  1766. TDocTemplate::SetFileFilter(const char far*)
  1767. {
  1768.   TRACEX(OwlDocView, 0, "Obsolete function called");
  1769. }
  1770.  
  1771. //
  1772. // Placeholder for an Obselete method - NOP.
  1773. //
  1774. void TDocTemplate::SetDescription(const char far*)
  1775. {
  1776.   TRACEX(OwlDocView, 0, "Obsolete function called");
  1777. }
  1778.  
  1779. //
  1780. //
  1781. //
  1782. void TDocTemplate::SetDefaultExt(const char far*)
  1783. {
  1784.   TRACEX(OwlDocView, 0, "Obsolete function called");
  1785. }
  1786. #endif
  1787.  
  1788. #endif  
  1789.